/*******************************************************************/
/* @ All Rights Reserved Copyright (C) 2014 broada,Co.,Ltd.        */
/*                                                                 */
/*  NAME      = sip_comm.c                                         */
/*  NOTE      =                                                    */
/*  DATE      = 2015/07/07 by songbb                               */
/*******************************************************************/

#include <stdio.h>
#include <memory.h>
#include <sys/time.h>
#include <frvar_field.h>

#include "frmem.h"
#include "frlog.h"
#include "frreport_comm.h"
#include "frct_comm.h"
#include "frexp_comm.h"
#include "frcomm.h"

#include "sip_core.h"
#include "sip_comm.h"

static char hex_asc[] = "0123456789abcdef";
#define hex_asc_lo(x)   hex_asc[((x) & 0x0f)]
#define hex_asc_hi(x)   hex_asc[((x) & 0xf0) >> 4]

extern void *g_p_apm_context;

/*******************************************************************************
*  FUNC     :  释放内存
*  ARGS     :  pp_buffer
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sip_free(void **pp_buffer)
{
    if (pp_buffer == NULL || *pp_buffer == NULL)
        return;

    frfree(*pp_buffer);
    *pp_buffer = NULL;
    return;
}

/*******************************************************************************
*  FUNC     :  时间格式化成 2015-03-29 22:25:12.448671 的格式
*  ARGS     :  *p_tv                           (时间戳)
*           :  *p_time                         (buffer)
*           :  ui_time_size                    (buffer size)
*  RTN      :
*  NOTE     :
*******************************************************************************/
FR_STATIC int __sip_frtime2datetimestr(struct timeval *p_tv
                                    , char *p_time
                                    , unsigned int ui_time_size)
{
    struct tm *p_tm = NULL;

    if(p_tv == NULL || p_time == NULL || ui_time_size <= 1)
        return FR_FAIL;

    p_tm = localtime(&(p_tv->tv_sec));

    snprintf(p_time,ui_time_size,"%04d-%02d-%02d %02d:%02d:%02d.%06ld",
             p_tm->tm_year + 1900,p_tm->tm_mon + 1,p_tm->tm_mday,
             p_tm->tm_hour,p_tm->tm_min,p_tm->tm_sec,p_tv->tv_usec);

    return FR_SUCC;
}

/*******************************************************************************
*  FUNC     :  时间转换
*  ARGS     :  *p_st_timestamp                     (时间戳)
*  RTN      :  转换后的时间值
*  NOTE     :
*******************************************************************************/
unsigned long sip_get_timestamp(struct timeval *p_st_timestamp)
{
    return (unsigned long) (p_st_timestamp->tv_sec*1000000 + p_st_timestamp->tv_usec);
}

/*******************************************************************************
*  FUNC     :  打印时间
*  ARGS     :  st_timestamp                         (时间戳)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void sip_print_timeval(struct timeval st_timestamp)
{
    char arr_buff[64];
    __sip_frtime2datetimestr(&st_timestamp, arr_buff, sizeof(arr_buff));
    printf(":[%s]\n", arr_buff);
}

/*******************************************************************************
*  FUNC     :  格式化成十六进制字符串
*  ARGS     :  *p_inbuff    (输入的字符串)
*           :  i_len        (输入的字符串长度)
*           :  *p_outbuff   (格式化后的十六进制字符串)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void sip_bin_to_hex_string(char *p_inbuff
                            , int i_len
                            , char *p_outbuff)
{
    int i_loop;
    char c;
    int i_used = 0;

    for (i_loop = 0; i_loop < i_len; i_loop++)
    {
        c = p_inbuff[i_loop];
        p_outbuff[i_used++] = hex_asc_hi(c);
        p_outbuff[i_used++] = hex_asc_lo(c);
    }

    return;
}

/*******************************************************************************
*  FUNC     :  按一个字节打印十六进行字符串
*  ARGS     :  *p_buff  (char*字符串)
*           :  i_len   (字符串长度)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void sip_print_hex_string(char *p_buff
                        , int i_len)
{
    int i_loop;

    for (i_loop = 0; i_loop < i_len; i_loop++)
        printf("%02x", p_buff[i_loop] & 0xFF);

    return;
}

/*******************************************************************************
*  FUNC     :  打印指定位置的包内容
*  ARGS     :  *p_st_sip_packet                     (SIP数据包)
*           :  i_pos                                (开始位置)
*           :  i_len                                (长度)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void sip_print_packet_specified(L7_sip_packet *p_st_sip_packet
                                , int i_pos
                                , int i_len)
{
    if (p_st_sip_packet == NULL)
        return;
    char *p_buff_tmp = NULL;
    if (bytebuff_show(p_st_sip_packet->p_st_packet, i_pos, i_len, &p_buff_tmp) != FR_SUCC)
        return;
    sip_print_hex_string(p_buff_tmp, i_len);
    sip_free((void **) &p_buff_tmp);
    return;
}

/*******************************************************************************
*  FUNC     :  打印当前位置开始的包内容
*  ARGS     :  *p_st_sip_packet                     (SIP数据包)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void sip_print_packet_current(L7_sip_packet *p_st_sip_packet)
{
    if (p_st_sip_packet == NULL)
        return;
    char *p_buff_tmp = NULL;
    if (bytebuff_show(p_st_sip_packet->p_st_packet, bytebuff_getPosition(p_st_sip_packet->p_st_packet), bytebuff_remaining(p_st_sip_packet->p_st_packet), &p_buff_tmp) != FR_SUCC)
        return;
    sip_print_hex_string(p_buff_tmp, bytebuff_remaining(p_st_sip_packet->p_st_packet));
    sip_free((void **) &p_buff_tmp);
    return;
}

/*******************************************************************************
*  FUNC     :  打印整个包内容
*  ARGS     :  *p_st_sip_packet                     (SIP数据包)
*  RTN      :
*  NOTE     :
*******************************************************************************/
void sip_print_packet(L7_sip_packet *p_st_sip_packet)
{
    if (p_st_sip_packet == NULL)
        return;
    char *p_buff_tmp = NULL;
    if (bytebuff_show(p_st_sip_packet->p_st_packet, 0, bytebuff_length(p_st_sip_packet->p_st_packet), &p_buff_tmp) != FR_SUCC)
        return;
    sip_print_hex_string(p_buff_tmp, bytebuff_length(p_st_sip_packet->p_st_packet));
    sip_free((void **) &p_buff_tmp);
    return;
}

/*******************************************************************************
*  FUNC     :  判断是否处于分片包状态
*  ARGS     :  *p_st_sip_packet                         (SIP数据包)
*  RTN      :  0                                        (FR_NO)
*              1                                        (FR_YES)
*  NOTE     :
*******************************************************************************/
int sip_packet_is_in_fragment(L7_sip_packet *p_st_sip_packet)
{
    if (p_st_sip_packet == NULL)
        return FR_NO;

    return (p_st_sip_packet->fragment_state == APM_SIP_FRAGMENT_NEED_NEXT_REQ_PACKET
            || p_st_sip_packet->fragment_state == APM_SIP_FRAGMENT_NEED_NEXT_RESP_PACKET) ? FR_YES : FR_NO;
}

/*******************************************************************************
*  FUNC     :  上报通信消息的响应信息
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_hash_report                        (数据上报)
*  RTN      :  0                                        (FR_SUCC)
*              1                                        (FR_FAIL)
*  NOTE     :
*******************************************************************************/
int sip_report_data(Conntrack *p_st_conn
                    , int i_is_req
                    , Frreport_body_data *p_st_body
                    , Frhash_header *p_st_hash_report)
{
    SIP_PRINT_INFO("sip_report_%s\n", i_is_req == FR_YES ? "req" : "resp");
    Frreport_data *p_st_report_data = NULL;

    if ((p_st_report_data = frreport_data_l7_new(i_is_req == FR_YES ? FRREPORT_TYPE_L7DATA_REQ : FRREPORT_TYPE_L7DATA_RESP)) == NULL)
        goto error;

    if (frreport_data_add_body(p_st_report_data, p_st_body) != FR_SUCC)
        goto error;

    if (frreport_data_hash(p_st_hash_report, p_st_report_data) != FR_SUCC)
        goto error;

    return FR_SUCC;
error:
    frreport_data_free(&p_st_report_data);
    return FR_FAIL;
}

/*******************************************************************************
*  FUNC     :  释放 L7_sip_stmt
*  ARGS     :  **pp_st_sip_stmt                             (L7_sip_stmt)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sip_free_stmt(L7_sip_stmt **pp_st_sip_stmt)
{
    if (pp_st_sip_stmt == NULL || *pp_st_sip_stmt == NULL)
        return;

    sip_free((void **) &((*pp_st_sip_stmt)->p_username));
    sip_free((void **) &((*pp_st_sip_stmt)->p_uri));
    sip_free((void **) &((*pp_st_sip_stmt)->p_ui_media_src_ip));
    sip_free((void **) &((*pp_st_sip_stmt)->p_ui_media_dst_ip));
    sip_free((void **) &((*pp_st_sip_stmt)->p_i_media_src_port));
    sip_free((void **) &((*pp_st_sip_stmt)->p_i_media_dst_port));

    frreport_body_l7list_free(&((*pp_st_sip_stmt)->p_report_comm));
    frreport_body_l7list_free(&((*pp_st_sip_stmt)->p_report_req));

    sip_free((void **) pp_st_sip_stmt);

    return;
}

/*******************************************************************************
*  FUNC     :  释放 stmt node节点
*  ARGS     :  *p_st_node                               (Frlist_node)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sip_stmt_node_free(Frlist_node *p_st_node)
{
    if (p_st_node == NULL || p_st_node->data == NULL)
        return;

    L7_sip_stmt *p_st_sip_stmt = (L7_sip_stmt *) FRLIST_GET_NODE_DATA(p_st_node);
    sip_free_stmt(&p_st_sip_stmt);
    p_st_node->data = NULL;
}

/*******************************************************************************
*  FUNC     :  设置子链路
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sip_stmt                           (对应的stmt)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sip_set_child_conn(Conntrack *p_st_conn
                        , L7_sip_stmt *p_st_sip_stmt)
{
    int i_loop1;
    int i_loop2;
    int i_loop3;
    int i_loop4;
    Frlist_header *p_lst_hdr = NULL;
    Frlist_node *p_st_node = NULL;
    Frvar_field *p_st_field = NULL;
    char arr_invite_time[32] = {'\0'};

    if (p_st_sip_stmt->p_ui_media_src_ip == NULL ||
        p_st_sip_stmt->p_i_media_src_port == NULL ||
        p_st_sip_stmt->p_ui_media_dst_ip == NULL ||
        p_st_sip_stmt->p_i_media_dst_port == NULL)
        goto error;

    if ((p_st_sip_stmt->i_media_src_ip_len > 1 && p_st_sip_stmt->i_media_src_port_len > 1) ||
            (p_st_sip_stmt->i_media_dst_ip_len > 1 && p_st_sip_stmt->i_media_dst_port_len > 1))
        goto error;

    snprintf(arr_invite_time, sizeof(arr_invite_time), "%lu", p_st_sip_stmt->ul_invite_begin_timestamp);

    for (i_loop1 = 0; i_loop1 < p_st_sip_stmt->i_media_src_ip_len; i_loop1++)
    {
        for (i_loop2 = 0; i_loop2 < p_st_sip_stmt->i_media_src_port_len; i_loop2++)
        {
            for (i_loop3 = 0; i_loop3 < p_st_sip_stmt->i_media_dst_ip_len; i_loop3++)
            {
                for (i_loop4 = 0; i_loop4 < p_st_sip_stmt->i_media_dst_port_len; i_loop4++)
                {
                    p_lst_hdr = frlist_create();
                    p_st_field = frvarfield_str(APM_SIP_INVITE_BEGIN_TIME, arr_invite_time);
                    p_st_node = frlist_node_create(p_st_field);
                    frlist_push(p_lst_hdr, p_st_node);

                    p_st_field = frvarfield_str(APM_SIP_INVITE_PLAY_URI, p_st_sip_stmt->p_uri);
                    p_st_node = frlist_node_create(p_st_field);
                    frlist_push(p_lst_hdr, p_st_node);

                    if (frexpect_add2(g_p_apm_context,
                                  p_st_sip_stmt->us_proto,
                                  p_st_sip_stmt->p_ui_media_src_ip[i_loop1],
                                  p_st_sip_stmt->p_i_media_src_port[i_loop2],
                                  p_st_sip_stmt->p_ui_media_dst_ip[i_loop3],
                                  p_st_sip_stmt->p_i_media_dst_port[i_loop4],
                                  50008,
                                  50008,
                                  50008,
                                  p_lst_hdr,
                                  p_st_conn) == FR_SUCC)
                    {
#if APM_SIP_DBG
                        char arr_src_ip[56];
                        char arr_dst_ip[56];
                        snprintf(arr_src_ip, sizeof(arr_src_ip), "%s", int_ntoa(p_st_sip_stmt->p_ui_media_src_ip[i_loop1]));
                        snprintf(arr_dst_ip, sizeof(arr_dst_ip), "%s", int_ntoa(p_st_sip_stmt->p_ui_media_dst_ip[i_loop3]));
                        SIP_PRINT_CRIT("src_ip:[%u] dst_ip:[%u]\n", p_st_sip_stmt->p_ui_media_src_ip[i_loop1], p_st_sip_stmt->p_ui_media_dst_ip[i_loop3]);
                        SIP_PRINT_CRIT("frexpect_add2 proto:[%d] src_ip:[%s] src_port:[%u] dst_ip:[%s] dst_port:[%u]\n",
                                       p_st_sip_stmt->us_proto,
                                       arr_src_ip,
                                       p_st_sip_stmt->p_i_media_src_port[i_loop2],
                                       arr_dst_ip,
                                       p_st_sip_stmt->p_i_media_dst_port[i_loop4]);
#endif
                    }
                    else
                    {
                        frexpect_free_param(&p_lst_hdr);
                        SIP_PRINT_CRIT("frexpect_add2 frexpect_free_param\n");
                    }
                }
            }
        }
    }

    sip_free((void **) &(p_st_sip_stmt->p_ui_media_src_ip));
    sip_free((void **) &(p_st_sip_stmt->p_ui_media_dst_ip));
    sip_free((void **) &(p_st_sip_stmt->p_i_media_src_port));
    sip_free((void **) &(p_st_sip_stmt->p_i_media_dst_port));
    p_st_sip_stmt->i_media_src_ip_len = 0;
    p_st_sip_stmt->i_media_src_port_len = 0;
    p_st_sip_stmt->i_media_dst_ip_len = 0;
    p_st_sip_stmt->i_media_dst_port_len = 0;
    return;
error:
    sip_free((void **) &(p_st_sip_stmt->p_ui_media_src_ip));
    sip_free((void **) &(p_st_sip_stmt->p_ui_media_dst_ip));
    sip_free((void **) &(p_st_sip_stmt->p_i_media_src_port));
    sip_free((void **) &(p_st_sip_stmt->p_i_media_dst_port));
    p_st_sip_stmt->i_media_src_ip_len = 0;
    p_st_sip_stmt->i_media_src_port_len = 0;
    p_st_sip_stmt->i_media_dst_ip_len = 0;
    p_st_sip_stmt->i_media_dst_port_len = 0;
    return;
}

/*******************************************************************************
*  FUNC     :  上报RTP协议相关的信息
*  ARGS     :  *p_st_sip_stmt                           (对应的stmt)
*           :  *p_st_body                               (Frreport_body_data)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
void sip_report_media_info(L7_sip_stmt *p_st_sip_stmt
                        , Frreport_body_data *p_st_body)
{
    SIP_PRINT_INFO("sip_report_media_info...\n");
    if (p_st_sip_stmt->p_ui_media_src_ip == NULL ||
        p_st_sip_stmt->p_i_media_src_port == NULL ||
        p_st_sip_stmt->p_ui_media_dst_ip == NULL ||
        p_st_sip_stmt->p_i_media_dst_port == NULL)
        goto error;

    if ((p_st_sip_stmt->i_media_src_ip_len > 1 && p_st_sip_stmt->i_media_src_port_len > 1) ||
        (p_st_sip_stmt->i_media_dst_ip_len > 1 && p_st_sip_stmt->i_media_dst_port_len > 1))
        goto error;

    if (frreport_body_l7_add_uint(p_st_body, APM_REPORT_KEY_REQ".rtp.media_ip", p_st_sip_stmt->p_ui_media_src_ip[0]) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_REQ".rtp.media_port", p_st_sip_stmt->p_i_media_src_port[0]) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_uint(p_st_body, APM_REPORT_KEY_RESP".rtp.media_ip", p_st_sip_stmt->p_ui_media_dst_ip[0]) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_int(p_st_body, APM_REPORT_KEY_RESP".rtp.media_port", p_st_sip_stmt->p_i_media_dst_port[0]) != FR_SUCC)
        goto error;
    if (frreport_body_l7_add_ulong(p_st_body, APM_REPORT_KEY_REQ"."APM_SIP_REPORT_MODULE_NAME".invite_start_time", p_st_sip_stmt->ul_invite_begin_timestamp) != FR_SUCC)
        goto error;

    sip_free((void **) &(p_st_sip_stmt->p_ui_media_src_ip));
    sip_free((void **) &(p_st_sip_stmt->p_ui_media_dst_ip));
    sip_free((void **) &(p_st_sip_stmt->p_i_media_src_port));
    sip_free((void **) &(p_st_sip_stmt->p_i_media_dst_port));
    p_st_sip_stmt->i_media_src_ip_len = 0;
    p_st_sip_stmt->i_media_src_port_len = 0;
    p_st_sip_stmt->i_media_dst_ip_len = 0;
    p_st_sip_stmt->i_media_dst_port_len = 0;
    return;
error:
    sip_free((void **) &(p_st_sip_stmt->p_ui_media_src_ip));
    sip_free((void **) &(p_st_sip_stmt->p_ui_media_dst_ip));
    sip_free((void **) &(p_st_sip_stmt->p_i_media_src_port));
    sip_free((void **) &(p_st_sip_stmt->p_i_media_dst_port));
    p_st_sip_stmt->i_media_src_ip_len = 0;
    p_st_sip_stmt->i_media_src_port_len = 0;
    p_st_sip_stmt->i_media_dst_ip_len = 0;
    p_st_sip_stmt->i_media_dst_port_len = 0;
    return;
}

/*******************************************************************************
*  FUNC     :  从Via字段中提取branch值
*  ARGS     :  *p_st_conn                               (ct信息)
*           :  *p_st_sess                               (SIP私有的session)
*  RTN      :  void
*  NOTE     :
*******************************************************************************/
int sip_get_branch_from_via(char *p_via
                            , char **pp_branch)
{
    char *p_branch = NULL;
    unsigned long ul_branch_len = 0;
    char *p_pos_start = NULL;
    char *p_pos_end = NULL;
    size_t ui_branchtag_len = strlen("branch=");

    if (p_via == NULL)
        goto error;

    if ((p_pos_start = strstr(p_via, "branch=")) == NULL ||
        p_pos_start - p_via + ui_branchtag_len == strlen(p_via))
        goto error;

    if ((p_pos_end = strchr(p_pos_start, ';')) != NULL)
    {
        if ((ul_branch_len = (p_pos_end - (p_pos_start + ui_branchtag_len))) == 0)
            goto error;
    }
    else
    {
        if ((ul_branch_len = strlen(p_via) - (p_pos_start + ui_branchtag_len - p_via)) == 0)
            goto error;
    }

    if ((p_branch = (char *) frmalloc(sizeof(char) * (ul_branch_len + 1))) == NULL)
    {
        SIP_MALLOCK_ERR;
        goto error;
    }
    memcpy(p_branch, p_pos_start + ui_branchtag_len, ul_branch_len);
    p_branch[ul_branch_len] = '\0';

    SIP_PRINT_CRIT("branch:[%s]\n", p_branch);

    *pp_branch = p_branch;

    return FR_SUCC;
error:
    sip_free((void **) &p_branch);
    return FR_FAIL;
}
